package com.example.lotterysystem.service.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;
import com.example.lotterysystem.common.utils.RedisUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.controller.param.ShowWinningRecordsParam;
import com.example.lotterysystem.dao.dataobject.*;
import com.example.lotterysystem.dao.mapper.*;
import com.example.lotterysystem.service.DrawPrizeService;
import com.example.lotterysystem.service.dto.WinningRecordDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.example.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.example.lotterysystem.common.config.DirectRabbitConfig.ROUTING;

/**
 * @auther falls_vc
 * description:
 * @date 2025/9/12  15:10
 */
@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {

    private static final Logger logger = LoggerFactory.getLogger(DrawPrizeServiceImpl.class);
    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";

    private final Long WINNING_RECORDS_TIMEOUT = 60*60*24*2L;

    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {
        ActivityDO activityDO= activityMapper.selectById(param.getActivityId());
        // 获得奖品信息
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(
                param.getActivityId(),param.getPrizeId()
        );
        // 活动是否存在
        if( null == activityDO || null == activityPrizeDO) {
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
            logger.warn("抽奖信息有误！错误原因：",ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY.getMsg());
            return false;
        }
        // 活动是否有效
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
            logger.warn("抽奖信息有误！错误原因：",ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMsg());
            return false;
        }

        // 奖品是否有效
        if(activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name())){
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED);
            logger.warn("抽奖信息有误！错误原因：",ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMsg());
            return false;
        }

        // 中奖者人数是否和设置奖品数量一致
        if(activityPrizeDO.getPrizeAmount() != param.getWinnerList().size()) {
//            throw new ServiceException(ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR);
            logger.warn("抽奖信息有误！错误原因：",ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {
        // 查询活动 奖品 中奖 人员 活动关联奖品 信息
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        PrizeDO prizeDO = prizeMapper.selectById(param.getPrizeId());
        List<UserDO> userDOList = userMapper.batchSelectByIds(param.getWinnerList()
                .stream()
                .map(DrawPrizeParam.Winner::getUserId)
                .collect(Collectors.toList())
        );

        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());

        // 构造中奖信息
        List<WinningRecordDO> winningRecordDOList = userDOList.stream().map(
                userDO -> {
                    WinningRecordDO winningRecordDO =new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDO.getId());
                    winningRecordDO.setActivityName(activityDO.getActivityName());
                    winningRecordDO.setPrizeId(prizeDO.getId());
                    winningRecordDO.setPrizeName(prizeDO.getName());
                    winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDO.setWinnerId(userDO.getId());
                    winningRecordDO.setWinnerName(userDO.getUserName());
                    winningRecordDO.setWinnerEmail(userDO.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());

                    return winningRecordDO;
                }
        ).collect(Collectors.toList());

        winningRecordMapper.batchInsert(winningRecordDOList);

        // 缓存中奖者记录 (redis)

        // 1.缓存奖品维度的中奖信息 (WinningRecord_activityId_prizeId ,winningRecordDOList（奖品维度中奖名单）)
        cacheWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),
                winningRecordDOList,
                            WINNING_RECORDS_TIMEOUT);

        // 2.缓存活动维度的中奖信息 (WinningRecord_activityId , winningRecordDOList)
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())) {
            // 所有维度的奖品中奖信息
            List<WinningRecordDO> allList = winningRecordMapper.selectByActivityId(param.getActivityId());

            cacheWinningRecords(String.valueOf(param.getActivityId()),
                                allList,
                                WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(null == activityId ) {
            logger.warn("要删中奖记录相关的活动id为空！");
            return;
        }
        // 1. 删除数据表
        winningRecordMapper.deleteRecords(activityId,prizeId);

        // 2. 删除缓存
        // 奖品维度
        if(prizeId != null) {
            deleteWinningRecords(activityId+"_"+prizeId);
        }
        // 活动维度 (无论是否传prizeId 都要删除活动记录)
        deleteWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParam param) {
        // 查询redis
        String key = null == param.getPrizeId()
                ? String.valueOf(param.getActivityId())
                : param.getActivityId() + "_" + param.getPrizeId();
        List<WinningRecordDO> winnerRecords = getWinnerRecords(key);
        if(!CollectionUtils.isEmpty(winnerRecords)) {
            return convertToWinningRecordDTOList(winnerRecords);
        }
        // redis不存在 查库
        winnerRecords = winningRecordMapper.selectByActivityIdOrPrizeId(param.getActivityId(),param.getPrizeId());
        // 缓存记录到redis
        if(CollectionUtils.isEmpty(winnerRecords)) {
            logger.warn("查询中奖记录为空！ param:{}",JacksonUtil.writeValueAsString(param));
            return Arrays.asList();
        }
        cacheWinningRecords(key,winnerRecords,WINNING_RECORDS_TIMEOUT);
        return convertToWinningRecordDTOList(winnerRecords);
    }

    private List<WinningRecordDTO> convertToWinningRecordDTOList(List<WinningRecordDO> winnerRecords) {
        if(CollectionUtils.isEmpty(winnerRecords)) {
            return Arrays.asList();
        }
        return winnerRecords.stream().map(winningRecordDO -> {
            WinningRecordDTO winningRecordDTO = new WinningRecordDTO();
            winningRecordDTO.setWinnerId(winningRecordDO.getWinnerId());
            winningRecordDTO.setWinnerName(winningRecordDO.getWinnerName());
            winningRecordDTO.setPrizeName(winningRecordDO.getPrizeName());
            winningRecordDTO.setPrizeTier(ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()));
            winningRecordDTO.setWinningTime(winningRecordDO.getWinningTime());
            return winningRecordDTO;
        }).collect(Collectors.toList());
    }

    private void deleteWinningRecords(String key) {
        try {
            if(redisUtil.hasKey(WINNING_RECORDS_PREFIX+key)) {
                redisUtil.delete(WINNING_RECORDS_PREFIX+key);
            }

        } catch (Exception e) {
            logger.error("删除缓存中奖记录异常！key:{}",key);
        }
    }

    /**
     * 缓存中奖记录
     *
     * @param key
     * @param winningRecordDOList
     * @param winning_records_timeout
     */
    private void cacheWinningRecords(String key, List<WinningRecordDO> winningRecordDOList, Long winning_records_timeout) {
        String str = "";
        try {
            if(!StringUtils.hasText(key)
                || CollectionUtils.isEmpty(winningRecordDOList)) {
                logger.warn("需要缓存的内容为空！key:{},value:{}",WINNING_RECORDS_PREFIX+key,JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }

            str = JacksonUtil.writeValueAsString(winningRecordDOList);
            redisUtil.set(WINNING_RECORDS_PREFIX+key,
                    str,
                    winning_records_timeout);
        } catch (Exception e) {
            logger.error("缓存中奖记录异常!key:{},value:{}",WINNING_RECORDS_PREFIX+key,str);

        }


    }

    /**
     * 从缓存中获取中奖记录
     *
     * @param key
     * @return
     */
    private List<WinningRecordDO> getWinnerRecords(String key) {
        try {
            if(!StringUtils.hasText(key)) {
                logger.warn("要从缓存中查询中奖信息的key为空！");
                return Arrays.asList();
            }

            String str = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if(str == null) {
                return Arrays.asList();
            }

            return JacksonUtil.readListValue(str, WinningRecordDO.class);
        } catch (Exception e) {
            logger.error("从缓存中查询中奖信息异常！key:{}",WINNING_RECORDS_PREFIX+key);
            return Arrays.asList();
        }
    }
    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String,String> map = new HashMap<>();
        map.put("messageId",String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));

        // 发消息: 交换机，绑定key ， 消息体
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, map);

        logger.info("mq消息发送成功：map:{}",JacksonUtil.writeValueAsString(map));
    }
}
